package com.rcloud.server.sealtalk.service;

import cn.hutool.http.HttpUtil;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import com.rcloud.server.sealtalk.model.tencent.Geth5faceidVo;
import com.rcloud.server.sealtalk.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author xiaochaoge
 * @title: FaceVerificationService
 * @projectName sealtalk-server
 * @description: TODO
 * @date 2022/3/214:40
 */

@Service
@Slf4j
public class FaceVerificationService {


    private static final String appId = "IDAkTH0Q";
    private static final String appSecret = "Qm8MMlD0ZK2zrP3ZpyZvBDDqMzvMid4kwZEgENBUiGgsoLEkW3UazFHjCE1GUo8L";
    private static final String version = "1.0.0";

    @Autowired
    private RedisUtils redisCache;

    public String getRequestFaceAccessToken() {
        String access_token = (String) redisCache.get("face_access_token");
        if (access_token != null && !"".equals(access_token)) {
            return access_token;
        }
        return getFaceAccessToken();
    }

    /**
     * 获取token
     */
    public String getFaceAccessToken() {
        StringBuffer url = new StringBuffer("https://miniprogram-kyc.tencentcloudapi.com/api/oauth2/access_token");
        url.append("?app_id=").append(appId);
        url.append("&secret=").append(appSecret);
        url.append("&grant_type=").append("client_credential");
        url.append("&version=").append(version);
        String returnData = HttpUtil.get(url.toString());
        log.info("getFaceAccessToken获取accessToken信息：：{}", returnData);
        if (!StringUtils.isEmpty(returnData)) {
            JSONObject jsonObject = JSON.parseObject(returnData);
            Map<String, Object> map = JSONObject.toJavaObject(jsonObject, Map.class);
            String accessToken = map.get("access_token") != null ? map.get("access_token").toString() : null;
            redisCache.set("face_access_token", accessToken, 60 * 20);
            return accessToken;
        }
        return null;
    }


    /**
     * 获取NonceTicket
     *
     * @param userId
     * @return
     */
    public String getFaceNonceTicket(String userId) {
        String accessToken = getRequestFaceAccessToken();
        StringBuffer url = new StringBuffer("https://miniprogram-kyc.tencentcloudapi.com/api/oauth2/api_ticket");
        url.append("?app_id=").append(appId);
        url.append("&access_token=").append(accessToken);
        url.append("&type=").append("NONCE");
        url.append("&version=").append(version);
        url.append("&user_id=").append(userId);
        String returnData = HttpUtil.get(url.toString());
        log.info("getFaceNonceTicket获取NonceTicket信息：：{}", returnData);
        if (returnData != null && !"".equals(returnData)) {
            JSONObject jsonObject = JSON.parseObject(returnData);
            Map<String, Object> map = JSONObject.toJavaObject(jsonObject, Map.class);
            log.info("getFaceNonceTicket获取NonceTicket信息：：{}", map);
            String tickets = map.get("tickets") != null ? map.get("tickets").toString() : null;

            if (tickets != null) {
                JSONArray jsonObjectT = JSON.parseArray(tickets);
                List<Map<String, Object>> listw = new ArrayList<Map<String, Object>>();
                for (Object object : jsonObjectT) {
                    Map<String, Object> ret = (Map<String, Object>) object;//取出list里面的值转为map
                    listw.add(ret);
                }

                String ticket = listw.get(0).get("value").toString();
                return ticket;
            }

        }
        return null;
    }

    /**
     * 签名算法
     *
     * @param values
     * @param ticket
     * @return
     */
    private static String signAlgorithm(List<String> values, String ticket) {
        if (values == null) {
            throw new NullPointerException("values is null");
        }
        values.removeAll(Collections.singleton(null));// remove null
        values.add(ticket);
        Collections.sort(values);

        StringBuilder sb = new StringBuilder();
        for (String s : values) {
            sb.append(s);
        }
        return Hashing.sha1().hashString(sb, Charsets.UTF_8).toString().toUpperCase();
    }

    /**
     * 获取SIGN ticket
     *
     * @return
     */
    public String getFaceSignTicket() {
        String ticket = (String) redisCache.get("face_sign_ticket");
        //String ticket = null;
        if (ticket != null && !"".equals(ticket)) {
            return ticket;
        }
        String accessToken = getRequestFaceAccessToken();
        StringBuffer url = new StringBuffer("https://miniprogram-kyc.tencentcloudapi.com/api/oauth2/api_ticket");
        url.append("?app_id=").append(appId);
        url.append("&access_token=").append(accessToken);
        url.append("&type=").append("SIGN");
        url.append("&version=").append(version);
        String returnData = HttpUtil.get(url.toString());
        log.info("getFaceNonceTicket获取NonceTicket信息：：{}", returnData);
        if (returnData != null && !"".equals(returnData)) {
            JSONObject jsonObject = JSON.parseObject(returnData);
            Map<String, Object> map = JSONObject.toJavaObject(jsonObject, Map.class);
            log.info("getFaceSignTicket获取NonceTicket信息：：{}", map);
            String tickets = map.get("tickets") != null ? map.get("tickets").toString() : null;

            if (tickets != null) {
                JSONArray jsonObjectT = JSON.parseArray(tickets);
                List<Map<String, Object>> listw = new ArrayList<Map<String, Object>>();
                for (Object object : jsonObjectT) {
                    Map<String, Object> ret = (Map<String, Object>) object;//取出list里面的值转为map
                    listw.add(ret);
                }
                ticket = listw.get(0).get("value").toString();// map1.get("value") != null ? map1.get("value").toString() : null;
                redisCache.set("face_sign_ticket", ticket, 60 * 20);
                return ticket;
            }

        }
        return null;
    }

    /**
     * easyface提供前端调用身份验证接口的参数
     */
    public Geth5faceidVo getFaceVerificationSignMap(String idCardNo, String name) {
        String userId = getZhiDingRandomNumStr(32, "userId");//32位随机码
        String ticket = getFaceSignTicket();
        Map<String, String> map = getFaceVerificationSign(userId,ticket);
        Geth5faceidVo returnMap = new Geth5faceidVo();
        //订单号，字母/数字组成的字符串，由合作方上送，每次唯一，不能超过32位
        String orderNo = getZhiDingRandomNumStr(32, "orderNo");//32位随机码
        returnMap.setNonce(map.get("nonce"));
        returnMap.setSign(map.get("sign"));
        returnMap.setOrderNo(orderNo);
        returnMap.setWebankAppId(appId);
        returnMap.setVersion(version);
        returnMap.setName(name);
        returnMap.setIdNo(idCardNo);
        returnMap.setUserId(userId);
        return returnMap;
    }

    /*
     * 生成签名  SIGN 类型
     *
     * */
    public Map<String, String> getFaceVerificationSign(String userId,String ticket) {
        log.info("ticket  {}", ticket);
        List<String> stringList = new ArrayList<>();
        stringList.add(appId);
        stringList.add(userId);//orderNo订单号，本次人脸核身合作伙伴上送的订单号，唯一标识
        String nonceStr = getZhiDingRandomNumStr(32, "NONCE");//32位随机码
        stringList.add(nonceStr);//nonce	随机数32位随机串（字母+数字组成的随机数）
        stringList.add(version);//版本号version

        Map<String, String> map = new HashMap<>();
        String sign = signAlgorithm(stringList, ticket);
        map.put("sign", sign);
        log.info("nonceStrLength={}", nonceStr.length());
        map.put("nonce", nonceStr);
        return map;
    }

    /*
     * H5人脸核身提供前端调用身份验证接口的参数
     * */
    public Map<String, String> getH5FaceVerificationSignMap(String name, String idNo) {
        String ticket = getFaceSignTicket();
        log.info("ticket  {}", ticket);
        List<String> stringList = new ArrayList<>();
        stringList.add(appId);
        String orderNo = getZhiDingRandomNumStr(32, "orderNo");//32位随机码
        stringList.add(orderNo);//orderNo订单号，本次人脸核身合作伙伴上送的订单号，唯一标识
        stringList.add(name);//姓名
        stringList.add(idNo);//身份证号
        String userId = getZhiDingRandomNumStr(32, "userId");//32位随机码
        stringList.add(userId);//用户 ID，用户的唯一标识（不要带有特殊字符）
        stringList.add(version);//版本号version

        Map<String, String> map = new HashMap<>();
        String sign = signAlgorithm(stringList, ticket);

        map.put("sign", sign);
        map.put("webankAppId", appId);
        map.put("orderNo", orderNo);
        map.put("name", name);
        map.put("idNo", idNo);
        map.put("userId", userId);
        map.put("version", version);

        log.info("map {}", map.toString());

        return map;
    }

    /**
     * 获取身份证查询签名   SIGN ticket 获取
     *
     * @return
     */
    public Map getSearchFaceVerificationSign(String orderNo, String nonceStr) {
        String ticket = getFaceSignTicket();
        List<String> stringList = new ArrayList<>();

        stringList.add(version);//版本号version
        stringList.add(appId);

        stringList.add(nonceStr);

        stringList.add(orderNo);//订单号

        Map<String, String> map = new HashMap<>();
        String sign = signAlgorithm(stringList, ticket);
        map.put("sign", sign);
        map.put("nonce", nonceStr);
        return map;
    }


    public static String getRandomNumStr(int length) {
        String base = "ABCDEFGHIJKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    public String getZhiDingRandomNumStr(Integer randomNumLength, String type) {
        String rNum = String.valueOf(System.currentTimeMillis());
        Integer typeLength = type.length();
        int i = randomNumLength - rNum.length() - typeLength;
        String nonceStr = type + rNum + getRandomNumStr(i);//32位随机码
        return nonceStr;
    }


}
